package com.googlecode.garbagecan.dbtest.vertica;

import com.googlecode.garbagecan.dbtest.Callback;
import com.googlecode.garbagecan.dbtest.util.DBUtil;

import java.sql.*;
import java.util.ArrayList;
import java.util.Formatter;
import java.util.List;
import java.util.Stack;

public class TestFastStorage {
	private static final String driver = "com.vertica.Driver";
//	private static final String url = "jdbc:vertica://perfqa04:5550/fkong";
//	private static final String username = "pa8";
//	private static final String password = "fkong";

	private static final String url = "jdbc:vertica://172.17.1.15:5433/simulate";
	//private static final String url = "jdbc:vertica://perf2:5433/simulate";
	private static final String username = "pa8";
	private static final String password  = "simulate";

	private static final int maxThread = 2;
	private static Integer runningThread = 0;
	
	private static Long totalSize = Long.valueOf(0);

	public static void main(String[] args) throws Exception {
		TestFastStorage ts = new TestFastStorage();
		ts.calculateDBSize();
		System.out.println(totalSize);
	}

	private void calculateDBSize() throws Exception {
		runningThread = 0;
		totalSize = Long.valueOf(0);
		
		final Stack<String> tables = new Stack<String>();
		String[] arrTables = new String[] {"AGGREGATE_INFO","BLD_LICUSAGE","DATALOADER_HEALTH","DPR_BYINTERVAL","EVENT","EVENT_MANAGER_CONF","EVENT_SOURCETYPE","FLEXLM_LICENSE_EVENTS","FLEXLM_LICENSE_USAGE","FLEXLM_LICENSE_USAGE_OLD","FLEXNET_LICENSE_EVENTS","FLEXNET_LICENSE_INFO","HOST_BOOLEANRES","HOST_CORE_UTILIZATION","HOST_GROUP","JOBS_PENDING_REASON","LSB_EVENTS","LSB_EVENTS_BAK1","LSB_EVENTS_EXECHOSTLIST","LSB_JOB_RUNTIMEHOST","LSB_JOB_STATUS","LSB_JOB_STATUS_PEND","LSF_BHOSTS","LSF_BHOSTS_BAK_S","LSF_BJOBS","LSF_BJOBS_BAK","LSF_BJOBS_BAK1","LSF_BQUEUES","LSF_PERFORMANCE_METRIC","LSF_RESOURCE_PROPERTIES","LSF_SLA","REGISTER_INFO","RESOURCE_ATTRIBUTES","RESOURCE_METRICS_BUILTIN","RESOURCE_METRICS_BUILTIN1","RESOURCE_METRICS_ELIM","SHARED_RESOURCE_USAGE","SHARED_RESOURCE_USAGE_HOSTLIST","SYS_ETL_HEALTH","SYS_HOSTLIST_STATUS_MAPPING","SYS_HOSTSLOT_STATUS_MAPPING","SYS_HOST_STATUS_MAPPING","SYS_OBJECT_INFO","SYS_PATCH_INFO","SYS_TABLES_TO_PARTITION","USER_GROUP","V_HARDWARE","aggREGATE_INFO2","aggREGATE_INFO_LARGER","lsb_events_long","lsf_bhosts_bak","register_info2"};
		for (final String table : arrTables) {
			tables.add(table);
		}

		while(true) {
			if (runningThread < maxThread) {
				Thread thread = new Thread(new Runnable() {
					public void run() {
						String table = "";
						synchronized (tables) {
							if (tables.size() == 0) {
								return;
							}
							table = tables.pop();
						}

						synchronized (runningThread) {
							runningThread++;
						}

						long size = 0;
						try {
							size = getTableSize(table);
						} catch (Exception e) {
							System.err.println("Table: " + table);
							//e.printStackTrace();
						}
						synchronized(totalSize) {
							totalSize += size;
						}
						synchronized (runningThread) {
							runningThread--;
						}
					}
				});
				thread.start();
			}

			Thread.sleep(1000);
			if (runningThread == 0 && tables.size() == 0) {
				break;
			}
		}
	}

	private long getTableSize(final String table) throws Exception {
		Connection conn = getConnection();

		String sTotalRecordNum = DBUtil.getSingleValue(conn, "SELECT count(*) FROM " + table);
		sTotalRecordNum = (sTotalRecordNum == null) ? "0" : sTotalRecordNum;

		String sql = "SELECT * FROM " + table + " where 1=0";
		PreparedStatement ps = conn.prepareStatement(sql);
		ResultSet rs = ps.executeQuery();
		ResultSetMetaData rsmd = rs.getMetaData();
		StringBuffer sbSQL = new StringBuffer();
		sbSQL.append("SELECT ");
		int colCount = rsmd.getColumnCount();
		for (int i = 1; i <= colCount; i++) {
			String columnName = rsmd.getColumnName(i);
			if (i != 1) {
				sbSQL.append("+");
			}
			sbSQL.append("SUM(LENGTH(NVL(").append(columnName).append("::VARCHAR, '')))");
		}
		sbSQL.append(" FROM ").append(table);
		rs.close();
		ps.close();

		String sTotalRecordSize = DBUtil.getSingleValue(conn, sbSQL.toString());
		long totalRecordSize = (sTotalRecordSize == null) ? 0 : Long.parseLong(sTotalRecordSize);
		sTotalRecordSize = getFormattedSize(totalRecordSize);

		StringBuffer sb = new StringBuffer();
		sb.append("\n==================================================");
		sb.append("\nTable               " + table);
		sb.append("\n--------------------------------------------------");
		sb.append("\nTotal Record Number " + sTotalRecordNum);
		sb.append("\nTotal Record Size   " + sTotalRecordSize);
		sb.append("\nExecute SQL         " + sbSQL.toString());
		sb.append("\n--------------------------------------------------");
		printMsg(sb.toString());

		conn.close();
		return totalRecordSize;
	}
	
	private String getFormattedSize(long size) {
		String ret = "";
		Formatter formatter = new Formatter();
		float fSize = (float)size;
		if (fSize >= ((1L<<40)) ) {
			ret = formatter.format("%.2f", fSize / 1024 / 1024 / 1024 / 1024).toString() + " TB";
		} else if (fSize >= (1L<<30) ) {
			ret = formatter.format("%.2f", fSize / 1024 / 1024 / 1024).toString() + " GB";
		} else if (fSize >= (1L<<20) ) {
			ret = formatter.format("%.2f", fSize / 1024 / 1024).toString() + " MB";
		} else if (fSize >= (1L<<10) ) {
			ret = formatter.format("%.2f", fSize / 1024 ).toString() + " KB";
		} else {
			ret = formatter.format("%.2f", fSize).toString() + " B";
		}
		return ret;
	}

	private Connection getConnection() throws Exception {
		Class.forName(driver);
		Connection conn = DriverManager.getConnection(url, username, password);
		conn.setAutoCommit(false);
		return conn;
	}

	private void doIt(Callback callback) throws Exception {
		long start = System.currentTimeMillis();
		callback.execute();
		long stop = System.currentTimeMillis();
		System.out.println("Time used: " + (stop - start) + " ms");
	}

	private synchronized void printMsg(String msg) {
		System.out.println(msg);
	}
}
